using Blog2025.Application.Configurations;
using Blog2025.Application.Dto;
using Blog2025.Application.Services;
using Blog2025.Application.Common;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text.Json;

namespace Blog2025.Application.Services;

/// <summary>
/// 文件上传服务实现
/// </summary>
public class FileUploadService : IFileUploadService
{
    private readonly FileUploadSettings _settings;
    private readonly ILogger<FileUploadService> _logger;

    public FileUploadService(
        IOptions<FileUploadSettings> settings,
        ILogger<FileUploadService> logger)
    {
        _settings = settings.Value;
        _logger = logger;
    }

    /// <summary>
    /// 验证上传文件
    /// </summary>
    public Task<FileValidationResultDto> ValidateFileAsync(IFormFile file)
    {
        var result = new FileValidationResultDto();
        var errors = new List<string>();

        try
        {
            // 检查文件是否为空
            if (file == null || file.Length == 0)
            {
                errors.Add("文件不能为空");
                result.IsValid = false;
                result.Errors = errors;
                return Task.FromResult(result);
            }

            // 检查文件大小
            if (file.Length > _settings.MaxFileSize)
            {
                errors.Add($"文件大小超过限制，最大允许 {_settings.MaxFileSize / (1024 * 1024)}MB");
            }

            // 检查文件扩展名
            var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
            if (!_settings.AllowedExtensions.Any(ext => ext.Equals(extension, StringComparison.OrdinalIgnoreCase)))
            {
                errors.Add($"不支持的文件类型 {extension}，允许的类型：{string.Join(", ", _settings.AllowedExtensions)}");
            }

            // 检查MIME类型
            if (!_settings.AllowedMimeTypes.Any(mime => mime.Equals(file.ContentType, StringComparison.OrdinalIgnoreCase)))
            {
                errors.Add($"不支持的文件MIME类型 {file.ContentType}");
            }

            result.IsValid = errors.Count == 0;
            result.Errors = errors;
            result.FileInfo = new FileInfoDto
            {
                FileName = file.FileName,
                FileSize = file.Length,
                Extension = extension,
                MimeType = file.ContentType
            };

            return Task.FromResult(result);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "文件验证时发生错误");
            result.IsValid = false;
            result.Errors = new List<string> { "文件验证时发生错误" };
            return Task.FromResult(result);
        }
    }

    /// <summary>
    /// 上传单个文件
    /// </summary>
    public async Task<ApiResult<FileUploadResultDto>> UploadFileAsync(IFormFile file, string? category = null)
    {
        try
        {
            // 验证文件
            var validation = await ValidateFileAsync(file);
            if (!validation.IsValid)
            {
                return ApiResult<FileUploadResultDto>.Failed(
                    string.Join("; ", validation.Errors),
                    400);
            }

            // 生成文件ID和存储路径
            var fileId = Guid.NewGuid().ToString("N");
            var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
            var storedFileName = $"{fileId}{extension}";

            // 构建存储路径
            var relativePath = BuildStoragePath(storedFileName, category);
            var fullPath = Path.Combine(_settings.StorageRootPath, relativePath);
            var directory = Path.GetDirectoryName(fullPath);

            // 确保目录存在
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory!);
            }

            // 保存文件
            using (var fileStream = new FileStream(fullPath, FileMode.Create))
            {
                await file.CopyToAsync(fileStream);
            }

            var result = new FileUploadResultDto
            {
                FileId = fileId,
                OriginalFileName = file.FileName,
                StoredFileName = storedFileName,
                FileSize = file.Length,
                Extension = extension,
                MimeType = file.ContentType,
                RelativePath = relativePath.Replace('\\', '/'),
                Url = GetFileUrl(relativePath.Replace('\\', '/')),
                UploadTime = DateTime.UtcNow
            };

            // 记录上传日志
            await LogFileUploadAsync(result);

            _logger.LogInformation("文件上传成功: {FileName} -> {StoredFileName}", 
                file.FileName, storedFileName);

            return ApiResult<FileUploadResultDto>.Success(result, "文件上传成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "文件上传失败: {FileName}", file.FileName);
            return ApiResult<FileUploadResultDto>.Failed("文件上传失败", 500);
        }
    }

    /// <summary>
    /// 批量上传文件
    /// </summary>
    public async Task<ApiResult<BatchUploadResultDto>> UploadFilesAsync(IFormFileCollection files, string? category = null)
    {
        var result = new BatchUploadResultDto
        {
            TotalCount = files.Count
        };

        foreach (var file in files)
        {
            var uploadResult = await UploadFileAsync(file, category);
            if (uploadResult.Succeeded)
            {
                result.SuccessFiles.Add(uploadResult.Data!);
                result.SuccessCount++;
            }
            else
            {
                result.FailedFiles.Add(new FailedFileDto
                {
                    FileName = file.FileName,
                    Errors = new List<string> { uploadResult.Message }
                });
                result.FailedCount++;
            }
        }

        var message = $"批量上传完成，成功 {result.SuccessCount} 个，失败 {result.FailedCount} 个";
        return ApiResult<BatchUploadResultDto>.Success(result, message);
    }

    /// <summary>
    /// 删除文件
    /// </summary>
    public async Task<ApiResult<bool>> DeleteFileAsync(string fileId)
    {
        try
        {
            // 查找文件记录
            var fileInfo = await GetFileInfoFromLogAsync(fileId);
            if (fileInfo == null)
            {
                return ApiResult<bool>.Failed("文件不存在", 404);
            }

            // 删除主文件
            var fullPath = Path.Combine(_settings.StorageRootPath, fileInfo.RelativePath);
            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
            }

            // 删除缩略图
            if (!string.IsNullOrEmpty(fileInfo.ThumbnailUrl))
            {
                var thumbnailPath = GetPhysicalPath(fileInfo.ThumbnailUrl);
                if (File.Exists(thumbnailPath))
                {
                    File.Delete(thumbnailPath);
                }
            }

            _logger.LogInformation("文件删除成功: {FileId}", fileId);
            return ApiResult<bool>.Success(true, "文件删除成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "文件删除失败: {FileId}", fileId);
            return ApiResult<bool>.Failed("文件删除失败", 500);
        }
    }

    /// <summary>
    /// 获取文件信息
    /// </summary>
    public async Task<ApiResult<FileUploadResultDto>> GetFileInfoAsync(string fileId)
    {
        try
        {
            var fileInfo = await GetFileInfoFromLogAsync(fileId);
            if (fileInfo == null)
            {
                return ApiResult<FileUploadResultDto>.Failed("文件不存在", 404);
            }

            return ApiResult<FileUploadResultDto>.Success(fileInfo, "获取文件信息成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取文件信息失败: {FileId}", fileId);
            return ApiResult<FileUploadResultDto>.Failed("获取文件信息失败", 500);
        }
    }

    /// <summary>
    /// 生成缩略图（简化版本）
    /// </summary>
    public Task<bool> GenerateThumbnailAsync(string sourceFilePath, string thumbnailFilePath, int width, int height)
    {
        // 简化实现，在实际项目中可以使用ImageSharp等库
        try
        {
            // 这里可以集成ImageSharp或其他图像处理库
            _logger.LogInformation("缩略图生成功能需要集成图像处理库");
            return Task.FromResult(false);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "生成缩略图失败");
            return Task.FromResult(false);
        }
    }

    /// <summary>
    /// 获取文件访问URL
    /// </summary>
    public string GetFileUrl(string relativePath)
    {
        return $"{_settings.BaseUrl.TrimEnd('/')}/uploads/{relativePath.TrimStart('/')}";
    }

    /// <summary>
    /// 清理过期临时文件
    /// </summary>
    public Task<int> CleanupExpiredFilesAsync(int expireDays = 7)
    {
        try
        {
            var expireDate = DateTime.UtcNow.AddDays(-expireDays);
            var cleanupCount = 0;
            var uploadDir = _settings.StorageRootPath;

            if (!Directory.Exists(uploadDir))
            {
                return Task.FromResult(0);
            }

            var files = Directory.GetFiles(uploadDir, "*", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                var fileInfo = new FileInfo(file);
                if (fileInfo.CreationTimeUtc < expireDate)
                {
                    try
                    {
                        File.Delete(file);
                        cleanupCount++;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "清理文件失败: {FilePath}", file);
                    }
                }
            }

            _logger.LogInformation("清理过期文件完成，共清理 {Count} 个文件", cleanupCount);
            return Task.FromResult(cleanupCount);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "清理过期文件时发生错误");
            return Task.FromResult(0);
        }
    }

    #region 私有方法

    /// <summary>
    /// 构建存储路径
    /// </summary>
    private string BuildStoragePath(string fileName, string? category = null)
    {
        var pathParts = new List<string>();

        if (!string.IsNullOrEmpty(category))
        {
            pathParts.Add(category);
        }

        if (_settings.OrganizeByDate)
        {
            pathParts.Add(DateTime.UtcNow.ToString(_settings.DateFolderFormat));
        }

        pathParts.Add(fileName);
        return Path.Combine(pathParts.ToArray());
    }

    /// <summary>
    /// 记录文件上传日志
    /// </summary>
    private async Task LogFileUploadAsync(FileUploadResultDto fileInfo)
    {
        try
        {
            var logDir = Path.Combine(_settings.StorageRootPath, "logs");
            if (!Directory.Exists(logDir))
            {
                Directory.CreateDirectory(logDir);
            }

            var logFile = Path.Combine(logDir, "upload_log.json");
            var logEntry = new
            {
                fileInfo.FileId,
                fileInfo.OriginalFileName,
                fileInfo.StoredFileName,
                fileInfo.RelativePath,
                fileInfo.FileSize,
                fileInfo.MimeType,
                fileInfo.UploadTime
            };

            var logJson = JsonSerializer.Serialize(logEntry);
            await File.AppendAllTextAsync(logFile, logJson + Environment.NewLine);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "记录上传日志失败");
        }
    }

    /// <summary>
    /// 从日志获取文件信息
    /// </summary>
    private async Task<FileUploadResultDto?> GetFileInfoFromLogAsync(string fileId)
    {
        try
        {
            var logFile = Path.Combine(_settings.StorageRootPath, "logs", "upload_log.json");
            if (!File.Exists(logFile))
            {
                return null;
            }

            var lines = await File.ReadAllLinesAsync(logFile);
            foreach (var line in lines.Reverse())
            {
                try
                {
                    var logEntry = JsonSerializer.Deserialize<FileUploadResultDto>(line);
                    if (logEntry?.FileId == fileId)
                    {
                        return logEntry;
                    }
                }
                catch
                {
                    continue;
                }
            }

            return null;
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// 获取物理路径
    /// </summary>
    private string GetPhysicalPath(string url)
    {
        var relativePath = url.Replace(_settings.BaseUrl, "").TrimStart('/');
        return Path.Combine(_settings.StorageRootPath, relativePath);
    }

    #endregion
}
